package com.zjf.fupload.popup.actions;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;
import java.net.URL;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.dialogs.Dialog;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.jface.dialogs.MessageDialog;
import org.eclipse.jface.resource.ImageDescriptor;
import org.eclipse.swt.SWT;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.events.KeyListener;
import org.eclipse.swt.events.SelectionEvent;
import org.eclipse.swt.events.SelectionListener;
import org.eclipse.swt.graphics.Image;
import org.eclipse.swt.graphics.ImageData;
import org.eclipse.swt.graphics.Point;
import org.eclipse.swt.layout.GridData;
import org.eclipse.swt.layout.GridLayout;
import org.eclipse.swt.program.Program;
import org.eclipse.swt.widgets.Combo;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Control;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Label;
import org.eclipse.swt.widgets.Listener;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.Table;
import org.eclipse.swt.widgets.TableColumn;
import org.eclipse.swt.widgets.TableItem;

import com.zjf.fupload.FUploadPlugin;
import com.zjf.fupload.entity.ServerInfo;
import com.zjf.fupload.ftp.FTPClientWrapper;
import com.zjf.fupload.ftp.FTPFileInfo;
import com.zjf.fupload.util.FileUtil;
  
/**
 * 选中服务器Dialog
 * @author zjf
 */
public class ChoosePathDialog extends Dialog {  
	
	private final DateFormat dformat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
	private final static String back_tip = "上级目录";
  
    public ChoosePathDialog(Shell parentShell) {
		super(parentShell);
		
		parentShell.addKeyListener(new KeyListener() {
			
			@Override
			public void keyReleased(KeyEvent arg0) {
				System.out.println(arg0);
			}
			
			@Override
			public void keyPressed(KeyEvent arg0) {
				System.out.println(arg0);
			}
		});
		
	}
  
    /**
	 * 服务器名称->服务器{@link ServerInfo}的映射
	 */
	private Map<String, ServerInfo> serverMap = new HashMap<String, ServerInfo>();
	
	private List<String> serverNames = new ArrayList<String>();
	
	private Table serverTable = null;
	private Table table = null;
	
	/** 
	 * 服务器上传路径
	 */
	private Combo historyPathCombo = null;
	
	private FTPClientWrapper ftpClient;
	private FTPFileInfo[] infos = new FTPFileInfo[0];
	private ServerInfo confirmServerInfo = null;
    
    @Override
	protected Control createDialogArea(Composite parent) {
    	this.getShell().setText(FUploadPlugin.NAME);
    	serverMap.clear();
		serverNames.clear();
		String[] serverInfos = FUploadPlugin.getDefault().getServersPreference();
			//new String[] {"cc:ftp.cc.ac.cn:21:anonymous:123:/pub",
		//"唯品会:ftp.cc.ac.cn:21:anonymous:123:/pub/netlib"};
		final List<ServerInfo> serverList = new ArrayList<ServerInfo>();
		for(String serverInfo : serverInfos) {
			ServerInfo info = ServerInfo.parse(serverInfo);
			if(info != null) {
				serverMap.put(info.getName(), info);
				serverNames.add(info.getName());
				serverList.add(info);
			}
		}
		
    	Composite container = (Composite) super.createDialogArea(parent);
    	container.setLayout(new GridLayout(3, true));
    	
    	Composite serverComposite = new Composite(container, SWT.NONE);
    	GridLayout serverGridLayout = new GridLayout(1, false);  
    	serverComposite.setLayout(serverGridLayout);
    	
    	GridData sgriddata = new GridData(GridData.FILL_BOTH);
    	sgriddata.horizontalSpan = 1;
    	serverComposite.setLayoutData(sgriddata);
    	
    	String[] serverTableHeader = {"名称", "路径"};
    	String[][] serverRows = new String[serverList.size()][];
    	for(int i=0; i<serverRows.length; i++) {
    		ServerInfo info = serverList.get(i);
    		serverRows[i] = new String[] {info.getName(), info.getPath()};
    	}
    	
    	serverTable = createTable(serverComposite, serverTableHeader, serverRows);
        serverTable.addListener(SWT.MouseDown, new Listener() {  
            public void handleEvent(Event e) {  
            	TableItem item = serverTable.getItem( new Point(e.x, e.y));
            	if(item != null) {
            		final String serverName = item.getText(0).trim();
            		runFunction(new Function() {
						public void run() throws Exception {
	            			ServerInfo info = serverMap.get(serverName);
	            			newFtpClient(info);
		            		updateTableDatas();
		            		String current = historyPathCombo.getText(); 
		            		historyPathCombo.removeAll();
		            		historyPathCombo.setText(current);
		            		historyPathCombo.add(current);
		            		String[] currentPathComponents = current.split("/");
		            		for(String path : FUploadPlugin.getDefault().getHistoryPathList().array()) {
		            			if(path.equalsIgnoreCase(current)) continue;
		            			String[] pathComponents = path.split("/");
		            			if(currentPathComponents.length > 1 && pathComponents.length > 1) {
		            				if(!currentPathComponents[1].equalsIgnoreCase(pathComponents[1])) {
		            					continue;
		            				}
		            			}
		            			historyPathCombo.add(path);
		            		}
						}
					});
            	}
            }  
        });  
        
		Composite composite = new Composite(container, SWT.NONE);  
		GridLayout gridLayout = new GridLayout(1, true); 
		composite.setLayout(gridLayout);  
		GridData griddata = new GridData(GridData.FILL_BOTH);
		griddata.horizontalSpan = 2;
		composite.setLayoutData(griddata);
		
		
		Composite pathComposite = new Composite(composite, SWT.NONE);
		GridLayout pathLayout = new GridLayout();  
		pathLayout.numColumns = 3;  
		pathLayout.horizontalSpacing = SWT.FILL;
		pathComposite.setLayout(pathLayout);
		GridData pathGD = new GridData(GridData.FILL_BOTH);
		pathComposite.setLayoutData(pathGD);
		
		Label label = new Label(pathComposite, SWT.NONE);
		label.setText("路径");
		URL imageURL = Platform.getBundle(FUploadPlugin.PROJECT_NAME).getEntry("icons/back.png");   
		Image image = ImageDescriptor.createFromURL(imageURL).createImage();
		label.setImage(image);
		label.addListener(SWT.MouseDown, new Listener() {
			public void handleEvent(Event e) {
				runFunction(new Function() {
					public void run() throws Exception {
						ftpClient.changeDirectoryUp();
	            		updateTableDatas();
					}
				});
			}
		});
		label.setToolTipText("点击到上级目录");
		
		historyPathCombo = new Combo(pathComposite, SWT.NULL);
	    
		GridData gridData = new GridData(GridData.FILL_BOTH);
		gridData.heightHint = 1;
		historyPathCombo.setLayoutData(gridData);
		 
		historyPathCombo.addSelectionListener(new SelectionListener() {
			@Override
			public void widgetSelected(SelectionEvent event) {
					final String selectd = historyPathCombo.getItem(historyPathCombo.getSelectionIndex());
					runFunction(new Function() {
						@Override
						public void run() throws Exception {
							ftpClient.changeDirectory(selectd);
							updateTableDatas();
						}
					});
			}
			@Override
			public void widgetDefaultSelected(SelectionEvent event) {
				
			}
		});
		
        Label goLabel = new Label(pathComposite, SWT.NONE);
        goLabel.setText("GO");
		URL goImageURL = Platform.getBundle(FUploadPlugin.PROJECT_NAME).getEntry("icons/go.png");   
		Image goImage = ImageDescriptor.createFromURL(goImageURL).createImage();
		goLabel.setImage(goImage);
		goLabel.addListener(SWT.MouseDown, new Listener() {
			public void handleEvent(Event e) {
				runFunction(new Function() {
					public void run() throws Exception {
						
						if(checkHasSelectServer()) {
							return;
						}
						
						String absPath = historyPathCombo.getText();
						absPath = absPath.trim();
						if(!absPath.startsWith("/")) {
							absPath = "/" + absPath;
						}
						ftpClient.changeDirectory(absPath);
	            		updateTableDatas();
					}
				});
			}
		});
		goLabel.setToolTipText("点击转到指定目录");
		
		// 创建表头的字符串数组  
        String[] tableHeader = {"名称                     ", "更改日期            ", "大小(byte)", "类型"};  
        String[][] rows = new String[15][4];
        for(int i=0; i<rows.length; i++) {
        	rows[i] = new String[] {"", "", "", ""};
        }

        Composite tableComposite = new Composite(composite, SWT.NONE);
		GridLayout tableLayout = new GridLayout();  
		tableLayout.numColumns = 1;  
		tableLayout.horizontalSpacing = SWT.FILL;
		tableComposite.setLayout(pathLayout);
		GridData tableGD = new GridData(GridData.FILL_BOTH);
		tableComposite.setLayoutData(tableGD);
        table = createTable(tableComposite, tableHeader, rows);
        table.addMouseListener(new RightMenuListener(this));  
        table.addListener(SWT.MouseDoubleClick, new Listener() {  
            public void handleEvent(Event e) {  
            	TableItem item = table.getItem( new Point(e.x, e.y));
            	if(item != null) {
            		
            		final String dirName = item.getText(0).trim();
            		final String type = item.getText(3).trim();
            		ChoosePathDialog.this.runFunction(new Function() {
						public void run() throws Exception {
							boolean shouldUpdate = false;
		            		if(String.valueOf(FTPFileInfo.TYPE_DIRECTORY).equals(type)) {
			            		ftpClient.changeDirectory(dirName);
			            		shouldUpdate = true;
		            		} else if(String.valueOf(FTPFileInfo.TYPE_LINK).equals(type)) {
		            			for(FTPFileInfo info : infos) {
		            				if(info.getName().equals(dirName)) {
		            					ftpClient.changeDirectory(info.getLink());
		            					shouldUpdate = true;
		            					break;
		            				}
		            			}
		            		} else if(back_tip.equals(dirName)) {
		            			ftpClient.changeDirectoryUp();
		            			shouldUpdate = true;
		            		}
		            		if(shouldUpdate) {
		            			updateTableDatas();
		            		}
						}
					});
            	}
            }  
        });  
        
//        if(!serverList.isEmpty()) {
//        	
//        	runFunction(new Function() {
//				public void run() throws Exception {
//					newFtpClient(serverList.get(0));
//					updateTableDatas();
//				}
//			});
//        }
        
//        uploadPathText.addKeyListener(new KeyListener() {
//			@Override
//			public void keyReleased(KeyEvent e) {
//			}
//			@Override
//			public void keyPressed(KeyEvent e) {
//				if (e.keyCode == 13) {  
//					String path = uploadPathText.getText().trim();
//					Pattern p = Pattern.compile("/?[^/]+(/[^/]+)*/?");
//					Matcher m = p.matcher(path);
//					if(!m.matches()) {
//						MessageDialog.openInformation(ChoosePathDialog.this.getShell(), 
//            					FUploadPlugin.NAME, "路径错误，请输入正确路径,如：/xx/xx/xxx");
//						return;
//					}
//					
//					if(!path.startsWith("/")) {
//						path = "/" + path;
//					}
//					
//					final String finalPath = path;
//					
//					runFunction(new Function() {
//						public void run() throws Exception {
//							ChoosePathDialog.this.ftpClient.changeDirectory(finalPath);
//							ChoosePathDialog.this.updateTableDatas();
//						}
//					});
//			    }  
//			}
//		});  
//        
//        uploadPathText.setFocus();
	        
    	return container;
    	
    }
    
    /**
	 * 保存选择的服务器，以便后续使用
	 */
	@Override
	protected void okPressed() {
		
		//验证是否选择了服务器
		if(checkHasSelectServer()) {
			return;
		}
		
		String serverName = serverTable.getItem(serverTable.getSelectionIndex()).getText(0);
		final ServerInfo info = serverMap.get(serverName);
		String path = historyPathCombo.getText().trim();
		path = normalizePath(path);
     	info.setPath(historyPathCombo.getText().trim());
		this.confirmServerInfo = info;
		
		//验证提供的路径合法性。
		runFunction(new Function() {
			@Override
			public void run() throws Exception {
				if(!ftpClient.currentDirectory().equalsIgnoreCase(info.getPath())) {
					ftpClient.changeDirectory(info.getPath());
		    	}
		    	ftpClient.disconnect(true);
			}
		});
		
		FUploadPlugin.getDefault().updateHistoryPathList(info.getPath());
		
		super.okPressed();
	}
	
	/**
	 * 
	 * @return true: 没有选择服务器，false： 选择了服务器
	 */
	private boolean checkHasSelectServer() {
		//验证是否选择了服务器
		if(ftpClient == null) {
			MessageDialog.openWarning(this.getShell(), FUploadPlugin.NAME, "您还没有选择服务器哦，请先选择服务器:)");
			return true;
		}
		return false;
	}
	
	private String normalizePath(String path) {
		assert path != null : "参数path不能为空";
		String returnPath = path.replaceAll("\\\\", "/");
		if(!returnPath.startsWith("/")) {
			returnPath = "/" + returnPath;
		}
		return returnPath;
	}
    
    private void newFtpClient(ServerInfo info) throws Exception {
		FTPClientWrapper tmpFtpClient = new FTPClientWrapper(info.getServer(), 
				info.getPort(), info.getPath(), 
				info.getUsername(), info.getPassword());
		tmpFtpClient.login();
		
		FTPClientWrapper oldFTPClient = ftpClient;
		ftpClient = tmpFtpClient;
		if(oldFTPClient != null) {
			oldFTPClient.disconnect(true);
    	}
    }
    
    private void updateTableDatas() throws Exception {
    	String currentPath = ftpClient.currentDirectory();
    	historyPathCombo.setText(currentPath);
    	
    	infos = ftpClient.list();
		String[][] datas = new String[infos.length + 1][4];
		datas[0] = new String[] {back_tip, " ", " ", " "};
		for(int i=0; i<infos.length; i++) {
			String date = "未知";
			if(infos[i].getModifiedDate() != null) {
				date = dformat.format(infos[i].getModifiedDate());
			}
			datas[i + 1] = new String[] { infos[i].getName(), date,
					String.valueOf(infos[i].getSize()), "" + infos[i].getType()};
		}
		updateTableDatas(table, datas);
    }
    
    protected void updateTableDatas(Table table, String[][] datas) {
		table.removeAll();
		for(int i=0; i < datas.length; i++) {
        	TableItem item = new TableItem(table, SWT.NONE);
        	String type = datas[i][3];
        	if(i == 0) {
        		URL imageURL = Platform.getBundle(FUploadPlugin.PROJECT_NAME).getEntry("icons/back.png");   
        		Image image = ImageDescriptor.createFromURL(imageURL).createImage();
        		item.setImage(0, image);
        	} else if(String.valueOf(FTPFileInfo.TYPE_DIRECTORY).equals(type)) {
        		URL imageURL = Platform.getBundle(FUploadPlugin.PROJECT_NAME).getEntry("icons/dir.png");   
        		Image image = ImageDescriptor.createFromURL(imageURL).createImage();
        		item.setImage(0, image);
        	} else {
        		URL imageURL = Platform.getBundle(FUploadPlugin.PROJECT_NAME).getEntry("icons/file.png");   
        		Image image = ImageDescriptor.createFromURL(imageURL).createImage();
        		
        		String fileName = datas[i][0];
        		String extension = FileUtil.getExtension(fileName);
        		if(!"".equals(extension)) {
        			Program p = Program.findProgram("." + extension);
        			if(p != null) {
        				ImageData data = p.getImageData();
        				image = new Image(table.getDisplay(), data);
        			}
        		}
        		
        		item.setImage(0, image);
        	}
            item.setText(datas[i]);  
        }
		
		table.redraw();
		
	}

	@Override
	protected Point getInitialSize(){
        return new Point(600, 520);//宽 高
    }
  
    // 创建表格  
    private Table createTable(Composite parent, String[] header, String[][] rows) {  
        // 表格布局  
        GridData gridData = new GridData();  
        gridData.horizontalAlignment = SWT.FILL;  
        gridData.grabExcessHorizontalSpace = true;  
        gridData.grabExcessVerticalSpace = true;  
        gridData.verticalAlignment = SWT.FILL;  
        gridData.verticalIndent = 2;
  
        // 创建表格，使用SWT.FULL_SELECTION样式，可选中一行  
        Table table = new Table(parent, SWT.BORDER | SWT.FULL_SELECTION);  
        table.setHeaderVisible(true);// 设置显示表头  
        table.setLayoutData(gridData);// 设置表格布局  
        table.setLinesVisible(true);// 设置显示表格线/*  
        
        for (int i = 0; i < header.length; i++) {  
            TableColumn tableColumn = new TableColumn(table, SWT.NONE);  
            tableColumn.setText(header[i]);  
            // 设置表头可移动，默认为false  
            tableColumn.setMoveable(true);  
        }  
        
        for(int i=0; i < rows.length; i++) {
        	TableItem item = new TableItem(table, SWT.NONE);
            item.setText(rows[i]);  
        }
       
        for (int i = 0; i < header.length; i++) {  
            table.getColumn(i).pack();  
        }  
        
        return table;
        
    }  
    
    public ServerInfo getConfirmServerInfo() {
		return confirmServerInfo;
	}
    
    protected Table getTable() {
    	return this.table;
    }
    
    protected FTPClientWrapper getFTPClient() {
    	return this.ftpClient;
    }

	protected void runFunction(Function f) {
		try {
			f.run();
		} catch (Exception expt) {
			ByteArrayOutputStream out = new ByteArrayOutputStream();
			PrintStream print = new PrintStream(out);
			expt.printStackTrace(print);
			
			// build the error message and include the current stack trace
			MultiStatus status = createMultiStatus(expt.getLocalizedMessage(), expt);
			// show error dialog
			ErrorDialog.openError(ChoosePathDialog.this.getShell(), FUploadPlugin.NAME, 
					  "发生错误：", status);
		}
	}
	
	private static MultiStatus createMultiStatus(String msg, Throwable t) {

		List<Status> childStatuses = new ArrayList<Status>();
		StackTraceElement[] stackTraces = t.getStackTrace();
		
		for (StackTraceElement stackTrace: stackTraces) {
		 Status status = new Status(IStatus.ERROR,
			  FUploadPlugin.PROJECT_NAME, stackTrace.toString());
		 childStatuses.add(status);
		}
		
		MultiStatus ms = new MultiStatus(FUploadPlugin.PROJECT_NAME,
		    IStatus.ERROR, childStatuses.toArray(new Status[] {}),
		    t.toString(), t);
		return ms;
	  }
	
	interface Function {
		void run() throws Exception;
	}
  
}  